<?php
namespace frame;
/**
* FramePHP 引导类
*/
class Frame{
	// 类映射
    private static $_map = array();
     // 实例化对象
    private static $_instance = array();

    //框架启动
    public static function start(){
      	//1.注册AUTOLOAD方法
      	spl_autoload_register('frame\Frame::autoload'); 
        register_shutdown_function('frame\Frame::fatalError');
        set_error_handler('frame\Frame::appError');
        set_exception_handler('frame\Frame::appException');

        //2.初始化文件存储方式
        Storage::connect(STORAGE_TYPE);
            /*设定错误和异常处理（PHP错误与异常处理,见https://www.cnblogs.com/zyf-zhaoyafei/p/6928149.html）
            Fatal Error:致命错误（脚本终止运行）
                E_ERROR         // 致命的运行错误，错误无法恢复，暂停执行脚本
                E_CORE_ERROR    // PHP启动时初始化过程中的致命错误
                E_COMPILE_ERROR // 编译时致命性错，就像由Zend脚本引擎生成了一个E_ERROR
                E_USER_ERROR    // 自定义错误消息。像用PHP函数trigger_error（错误类型设置为：E_USER_ERROR）

            Parse Error：编译时解析错误，语法错误（脚本终止运行）
                E_PARSE  //编译时的语法解析错误

            Warning Error：警告错误（仅给出提示信息，脚本不终止运行）
                E_WARNING         // 运行时警告 (非致命错误)。
                E_CORE_WARNING    // PHP初始化启动过程中发生的警告 (非致命错误) 。
                E_COMPILE_WARNING // 编译警告
                E_USER_WARNING    // 用户产生的警告信息

            Notice Error：通知错误（仅给出通知信息，脚本不终止运行）
                E_NOTICE      // 运行时通知。表示脚本遇到可能会表现为错误的情况.
                E_USER_NOTICE // 用户产生的通知信息。
            */

        // 读取应用模式(配置文件、别名定义、函数和类文件、行为扩展定义)
        $mode   =   include is_file(CONF_PATH.'core.php')? CONF_PATH.'core.php' : MODE_PATH.APP_MODE.'.php';
            // 加载核心文件
        foreach ($mode['core'] as $file){
            if(is_file($file)) {
                include $file;
                if(!APP_DEBUG) $content   .= compile($file);
            }
        }          
      	// 加载应用模式配置文件
      	foreach ($mode['config'] as $key=>$file){
      		if(is_file($file)){
      			is_numeric($key)?C(load_config($file)):C($key,load_config($file));
      		}
      	}
    	 // 加载框架底层语言包
          //L(include FRAME_PATH.'lang/'.strtolower(C('DEFAULT_LANG')).'.php');
            // 设置系统时区
          date_default_timezone_set(C('DEFAULT_TIMEZONE'));
            // 运行应用
          App::run();
    }

    //类的自动加载
    public static function autoload($class){
    	// 检查是否存在映射
    	if(isset(self::$_map[$class])){
			   return true;
  		}elseif(false !== strpos($class,'\\')){
  			//如果设置为 "true"，它将返回 search 参数第一次出现之前的字符串部分。
            $name = strstr($class, '\\', true);
            if(in_array($name,array('frame')) || is_dir(LIB_PATH.$name)){ 
           	   $path = LIB_PATH;
            }else{
            	// 检测自定义命名空间 否则就以模块为命名空间
                $namespace  =   C('AUTOLOAD_NAMESPACE');
                $path       =   isset($namespace[$name])? dirname($namespace[$name]).'/' : APP_PATH;
            }	
  			    $filename  =  $path . str_replace('\\', '/', $class) . EXT;
            if(is_file($filename)) {
                   // Windows环境下面严格区分大小写 
    	        if(IS_WIN && false === strpos(str_replace('/', '\\', realpath($filename)), $class . EXT)){
    	          return ;
    	        }
                include $filename;
            }
  		}elseif (!C('APP_USE_NAMESPACE')){
  		}
    }

    //致命错误捕获 register_shutdown_function函数是来注册一个会在PHP中止时执行的函数(1.执行完成;2.exit/die导致的中止;3.发生致命错误中止)
    static public function fatalError() {
        //Log::save();
        //获取关于最后一个发生的错误的信息
        if($e = error_get_last()) {
	          // switch($e['type']){
	          //   case E_ERROR:
	          //   case E_PARSE:
	          //   case E_CORE_ERROR:
	          //   case E_COMPILE_ERROR:
	          //   case E_USER_ERROR:  
	          //     ob_end_clean();
	          //     self::halt($e);
	          //     break;
	          // }
        }
    }

    /**
     * 自定义错误处理（set_error_handler只能捕获系统产生的一些Warning、Notice级别的Error。）
     * @param int $errno 错误类型
     * @param string $errstr 错误信息
     * @param string $errfile 错误文件
     * @param int $errline 错误行数
     * @return void
     */
    static public function appError($errno, $errstr, $errfile, $errline) {
        dump($errno.'warning'.$errstr);
      // switch ($errno) {
      //     case E_ERROR:
      //     case E_PARSE:
      //     case E_CORE_ERROR:
      //     case E_COMPILE_ERROR:
      //     case E_USER_ERROR:
      //       ob_end_clean();
      //       $errorStr = "$errstr ".$errfile." 第 $errline 行.";
      //       if(C('LOG_RECORD')) Log::write("[$errno] ".$errorStr,Log::ERR);
      //       self::halt($errorStr);
      //       break;
      //     default:
      //       $errorStr = "[$errno] $errstr ".$errfile." 第 $errline 行.";
      //       self::trace($errorStr,'','NOTIC');
      //       break;
      // }
    }

      /**
     * 取得对象实例 支持调用类的静态方法
     * @param string $class 对象类名
     * @param string $method 类的静态方法名
     * @return object
     */
    static public function instance($class,$method='') {
        $identify   =   $class.$method;//相当于索引
        if(!isset(self::$_instance[$identify])) {
            if(class_exists($class)){
                $o = new $class();
                if(!empty($method) && method_exists($o,$method)){
                	self::$_instance[$identify] = call_user_func(array(&$o, $method));
                }else{
                	//一般走下面
                	self::$_instance[$identify] = $o;
                }  
            }
            else{
            	//类不存在
                //self::halt(L('_CLASS_NOT_EXIST_').':'.$class);
            }
        }
        return self::$_instance[$identify];
    }

     /**
     * 自定义异常处理
     * @access public
     * @param mixed $e 异常对象
     */
    static public function appException($e) {
        $error = array();
        $error['message']   =   $e->getMessage();
        $trace              =   $e->getTrace();
        if('E'==$trace[0]['function']) {
            $error['file']  =   $trace[0]['file'];
            $error['line']  =   $trace[0]['line'];
        }else{
            $error['file']  =   $e->getFile();
            $error['line']  =   $e->getLine();
        }
        $error['trace']     =   $e->getTraceAsString();
        Log::record($error['message'],Log::ERR);
        // 发送404信息
        header('HTTP/1.1 404 Not Found');
        header('Status:404 Not Found');
        self::halt($error);
    }


}